import * as vscode from 'vscode';
import { spawn, ChildProcess } from 'child_process';
import * as readline from 'readline';
import { Environment } from './environmentDetector';
import { ContainerManager } from './containerManager';

/**
 * 日志类型
 */
export enum LogType {
    ACCESS = 'access',
    ERROR = 'error',
    ALL = 'all'
}

/**
 * 日志筛选条件
 */
export interface LogFilter {
    type?: LogType;
    pattern?: string;
    statusCodes?: number[];
    fromTime?: Date;
    toTime?: Date;
    minLevel?: string; // debug, info, warn, error, etc.
}

/**
 * 日志条目接口
 */
export interface LogEntry {
    timestamp: Date;
    type: LogType;
    message: string;
    level?: string;
    statusCode?: number;
    path?: string;
    ip?: string;
    method?: string;
    highlighted?: boolean;
    lineNumber?: number; // 对应配置文件的行号，用于错误关联
    configPath?: string; // 关联的配置文件路径
}

/**
 * 日志查看器类
 */
export class LogViewer {
    private outputChannel: vscode.OutputChannel;
    private errorDiagnosticCollection: vscode.DiagnosticCollection;
    private logProcess: ChildProcess | null = null;
    private containerManager: ContainerManager;
    private environment: Environment;
    private logEntries: LogEntry[] = [];
    private statusBarItem: vscode.StatusBarItem;
    private refreshInterval: NodeJS.Timeout | null = null;
    private activeFilters: LogFilter = {};
    public isStreaming: boolean = false;

    constructor(environment: Environment) {
        this.outputChannel = vscode.window.createOutputChannel('Nginx Logs');
        this.errorDiagnosticCollection = vscode.languages.createDiagnosticCollection('nginx-logs');
        this.containerManager = new ContainerManager(environment);
        this.environment = environment;
        this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
        this.statusBarItem.text = '$(terminal) Nginx Logs';
        this.statusBarItem.tooltip = 'Show Nginx Logs';
        this.statusBarItem.command = 'nginx-config-visualizer.showLogs';
        this.statusBarItem.show();
    }

    /**
     * 开始实时日志流
     */
    async startLogStream(containerName: string, logType: LogType = LogType.ALL): Promise<void> {
        // 停止任何现有的日志流
        this.stopLogStream();

        try {
            this.isStreaming = true;
            this.updateStatusBarItem(true);
            
            // 根据环境选择不同的命令
            let command: string;
            let args: string[];
            
            if (this.environment.type === 'podman') {
                command = 'podman';
                args = ['logs', '-f', containerName];
            } else if (this.environment.type === 'docker') {
                command = 'docker';
                args = ['logs', '-f', containerName];
            } else {
                this.outputChannel.appendLine('无法启动日志流：没有检测到容器环境');
                return;
            }
            
            // 如果指定了具体的日志类型，添加相应的参数
            if (logType === LogType.ACCESS) {
                // 在大多数Nginx容器配置中，访问日志通常输出到stdout
                args.push('--stdout');
            } else if (logType === LogType.ERROR) {
                // 错误日志通常输出到stderr
                args.push('--stderr');
            }
            
            this.outputChannel.appendLine(`启动 ${containerName} 的日志流...`);
            this.outputChannel.show(true);
            
            // 启动日志进程
            this.logProcess = spawn(command, args);
            
            // 处理标准输出
            const stdoutReader = readline.createInterface({
                input: this.logProcess.stdout!,
                terminal: false,
            });
            
            stdoutReader.on('line', (line) => {
                const entry = this.parseLogLine(line, LogType.ACCESS);
                if (entry && this.matchesFilter(entry, this.activeFilters)) {
                    this.logEntries.push(entry);
                    this.outputChannel.appendLine(this.formatLogEntry(entry));
                }
            });
            
            // 处理标准错误
            const stderrReader = readline.createInterface({
                input: this.logProcess.stderr!,
                terminal: false,
            });
            
            stderrReader.on('line', (line) => {
                const entry = this.parseLogLine(line, LogType.ERROR);
                if (entry && this.matchesFilter(entry, this.activeFilters)) {
                    this.logEntries.push(entry);
                    this.outputChannel.appendLine(this.formatLogEntry(entry));
                    
                    // 尝试关联错误日志到配置文件
                    this.tryLinkErrorToConfig(entry);
                }
            });
            
            // 处理进程退出
            this.logProcess.on('close', (code) => {
                this.isStreaming = false;
                this.updateStatusBarItem(false);
                this.outputChannel.appendLine(`日志流已终止，退出代码：${code}`);
            });
            
            this.logProcess.on('error', (error) => {
                this.isStreaming = false;
                this.updateStatusBarItem(false);
                this.outputChannel.appendLine(`日志流出错：${error.message}`);
                vscode.window.showErrorMessage(`获取Nginx日志失败：${error.message}`);
            });
            
        } catch (error) {
            this.isStreaming = false;
            this.updateStatusBarItem(false);
            this.outputChannel.appendLine(`启动日志流失败：${error instanceof Error ? error.message : String(error)}`);
            vscode.window.showErrorMessage(`启动Nginx日志流失败：${error instanceof Error ? error.message : String(error)}`);
        }
    }

    /**
     * 停止日志流
     */
    stopLogStream(): void {
        if (this.logProcess) {
            this.logProcess.kill();
            this.logProcess = null;
            this.isStreaming = false;
            this.updateStatusBarItem(false);
            this.outputChannel.appendLine('日志流已停止');
        }
        
        if (this.refreshInterval) {
            clearInterval(this.refreshInterval);
            this.refreshInterval = null;
        }
    }

    /**
     * 获取日志条目列表
     */
    getLogEntries(): LogEntry[] {
        return [...this.logEntries];
    }

    /**
     * 应用日志过滤器
     */
    applyFilter(filter: LogFilter): void {
        this.activeFilters = filter;
        this.refreshLogView();
    }

    /**
     * 清除所有过滤器
     */
    clearFilters(): void {
        this.activeFilters = {};
        this.refreshLogView();
    }

    /**
     * 刷新日志视图，应用过滤器
     */
    refreshLogView(): void {
        this.outputChannel.clear();
        
        const filteredEntries = this.logEntries.filter(entry => 
            this.matchesFilter(entry, this.activeFilters)
        );
        
        for (const entry of filteredEntries) {
            this.outputChannel.appendLine(this.formatLogEntry(entry));
        }
        
        this.outputChannel.appendLine(`显示 ${filteredEntries.length} 条日志（共 ${this.logEntries.length} 条）`);
    }

    /**
     * 显示日志视图
     */
    showLogs(): void {
        this.outputChannel.show(true);
    }

    /**
     * 导出日志到文件
     */
    async exportLogs(filePath: string): Promise<void> {
        try {
            const fs = require('fs');
            const filteredEntries = this.logEntries.filter(entry => 
                this.matchesFilter(entry, this.activeFilters)
            );
            
            let content = '';
            for (const entry of filteredEntries) {
                content += this.formatLogEntry(entry) + '\n';
            }
            
            fs.writeFileSync(filePath, content);
            vscode.window.showInformationMessage(`日志已导出到 ${filePath}`);
        } catch (error) {
            vscode.window.showErrorMessage(`导出日志失败：${error instanceof Error ? error.message : String(error)}`);
        }
    }

    /**
     * 检查日志条目是否匹配过滤器
     */
    private matchesFilter(entry: LogEntry, filter: LogFilter): boolean {
        // 如果没有设置过滤器，所有日志都匹配
        if (!filter || Object.keys(filter).length === 0) {
            return true;
        }
        
        // 检查日志类型
        if (filter.type && filter.type !== LogType.ALL && entry.type !== filter.type) {
            return false;
        }
        
        // 检查文本模式
        if (filter.pattern && !entry.message.includes(filter.pattern)) {
            return false;
        }
        
        // 检查状态码
        if (filter.statusCodes && filter.statusCodes.length > 0 && 
            entry.statusCode && !filter.statusCodes.includes(entry.statusCode)) {
            return false;
        }
        
        // 检查时间范围
        if (filter.fromTime && entry.timestamp < filter.fromTime) {
            return false;
        }
        
        if (filter.toTime && entry.timestamp > filter.toTime) {
            return false;
        }
        
        // 检查日志级别
        if (filter.minLevel && entry.level) {
            const levels = ['debug', 'info', 'notice', 'warn', 'error', 'crit', 'alert', 'emerg'];
            const minLevelIndex = levels.indexOf(filter.minLevel);
            const entryLevelIndex = levels.indexOf(entry.level);
            
            if (minLevelIndex !== -1 && entryLevelIndex !== -1 && entryLevelIndex < minLevelIndex) {
                return false;
            }
        }
        
        return true;
    }

    /**
     * 格式化日志条目，包括颜色高亮
     */
    private formatLogEntry(entry: LogEntry): string {
        // 获取时间戳部分
        const timestamp = entry.timestamp.toISOString();
        
        // 根据日志类型和级别，决定不同的格式
        let prefix = '';
        if (entry.type === LogType.ERROR) {
            prefix = `[ERROR] `;
        } else if (entry.type === LogType.ACCESS) {
            prefix = `[ACCESS] `;
            
            // 如果有HTTP状态码，根据状态码添加不同颜色
            if (entry.statusCode) {
                if (entry.statusCode >= 500) {
                    prefix = `[ACCESS][500] `; // 服务器错误
                } else if (entry.statusCode >= 400) {
                    prefix = `[ACCESS][400] `; // 客户端错误
                } else if (entry.statusCode >= 300) {
                    prefix = `[ACCESS][300] `; // 重定向
                } else {
                    prefix = `[ACCESS][200] `; // 成功
                }
            }
        }
        
        // 如果有关联的配置行
        let configInfo = '';
        if (entry.configPath && entry.lineNumber) {
            configInfo = ` (配置: ${entry.configPath}:${entry.lineNumber})`;
        }
        
        return `${timestamp} ${prefix}${entry.message}${configInfo}`;
    }

    /**
     * 解析日志行，提取结构化信息
     */
    private parseLogLine(line: string, defaultType: LogType): LogEntry | null {
        try {
            const now = new Date();
            
            // 基本日志条目
            const entry: LogEntry = {
                timestamp: now,
                type: defaultType,
                message: line
            };
            
            // 尝试从不同格式的日志中提取信息
            if (defaultType === LogType.ACCESS) {
                // 尝试解析访问日志格式 (常见的组合日志格式)
                // 例如: 127.0.0.1 - - [21/Jul/2023:10:15:32 +0000] "GET /index.html HTTP/1.1" 200 2458 "-" "Mozilla/5.0"
                const accessLogRegex = /(\S+) (\S+) (\S+) \[(.*?)\] "(\S+) (\S+) (\S+)" (\d+) (\d+)/;
                const match = line.match(accessLogRegex);
                
                if (match) {
                    entry.ip = match[1];
                    const dateStr = match[4];
                    entry.method = match[5];
                    entry.path = match[6];
                    entry.statusCode = parseInt(match[8], 10);
                    
                    // 尝试解析日志中的时间戳
                    try {
                        // 将Nginx日志时间格式转换为JS Date
                        const dateParts = /(\d+)\/(\w+)\/(\d+):(\d+):(\d+):(\d+)/.exec(dateStr);
                        if (dateParts) {
                            const months: {[key: string]: number} = {
                                'Jan': 0, 'Feb': 1, 'Mar': 2, 'Apr': 3, 'May': 4, 'Jun': 5,
                                'Jul': 6, 'Aug': 7, 'Sep': 8, 'Oct': 9, 'Nov': 10, 'Dec': 11
                            };
                            
                            const day = parseInt(dateParts[1], 10);
                            const month = months[dateParts[2]];
                            const year = parseInt(dateParts[3], 10);
                            const hour = parseInt(dateParts[4], 10);
                            const minute = parseInt(dateParts[5], 10);
                            const second = parseInt(dateParts[6], 10);
                            
                            if (!isNaN(day) && month !== undefined && !isNaN(year) && 
                                !isNaN(hour) && !isNaN(minute) && !isNaN(second)) {
                                entry.timestamp = new Date(year, month, day, hour, minute, second);
                            }
                        }
                    } catch (error) {
                        console.error('Error parsing log timestamp:', error);
                    }
                }
            } else if (defaultType === LogType.ERROR) {
                // 尝试解析错误日志格式
                // 例如: 2023/07/21 10:15:32 [error] 12345#0: *2 open() "/etc/nginx/html/favicon.ico" failed (2: No such file or directory)
                const errorLogRegex = /(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}) \[(\w+)\] .*?: (.+)/;
                const match = line.match(errorLogRegex);
                
                if (match) {
                    const dateStr = match[1];
                    entry.level = match[2].toLowerCase();
                    entry.message = match[3];
                    
                    // 尝试解析日志中的时间戳
                    try {
                        const [datePart, timePart] = dateStr.split(' ');
                        const [year, month, day] = datePart.split('/').map(Number);
                        const [hour, minute, second] = timePart.split(':').map(Number);
                        
                        entry.timestamp = new Date(year, month - 1, day, hour, minute, second);
                    } catch (error) {
                        console.error('Error parsing error log timestamp:', error);
                    }
                    
                    // 尝试解析配置错误位置
                    this.parseConfigErrorLocation(entry);
                }
            }
            
            return entry;
        } catch (error) {
            console.error('Error parsing log line:', error);
            return {
                timestamp: new Date(),
                type: defaultType,
                message: line
            };
        }
    }

    /**
     * 尝试从错误日志中解析配置错误位置
     */
    private parseConfigErrorLocation(entry: LogEntry): void {
        // 尝试匹配各种错误模式，提取配置文件路径和行号
        const patterns = [
            // 配置文件语法错误: nginx: [emerg] directive "server" has no opening "{" in /etc/nginx/conf.d/default.conf:10
            /directive .* in (.*):(\d+)/,
            // 配置文件路径错误: nginx: [error] open() "/etc/nginx/conf.d/missing.conf" failed (2: No such file or directory)
            /open\(\) "(.*)" failed/,
            // 其他可能的错误模式...
        ];
        
        for (const pattern of patterns) {
            const match = entry.message.match(pattern);
            if (match) {
                if (match.length >= 3) {
                    // 如果匹配到了文件路径和行号
                    entry.configPath = match[1];
                    entry.lineNumber = parseInt(match[2], 10);
                } else if (match.length >= 2) {
                    // 如果只匹配到了文件路径
                    entry.configPath = match[1];
                }
                break;
            }
        }
    }

    /**
     * 尝试将错误日志关联到配置文件
     */
    private async tryLinkErrorToConfig(entry: LogEntry): Promise<void> {
        if (!entry.configPath || !entry.lineNumber) {
            return;
        }
        
        try {
            // 创建一个诊断信息，显示在配置文件中
            const uri = vscode.Uri.file(entry.configPath);
            
            // 尝试读取文件内容
            try {
                const document = await vscode.workspace.openTextDocument(uri);
                const lineIndex = Math.max(0, entry.lineNumber - 1);
                const line = document.lineAt(lineIndex);
                
                const range = new vscode.Range(
                    new vscode.Position(lineIndex, 0),
                    line.range.end
                );
                
                const diagnostic = new vscode.Diagnostic(
                    range,
                    `Nginx错误: ${entry.message}`,
                    vscode.DiagnosticSeverity.Error
                );
                
                this.errorDiagnosticCollection.set(uri, [diagnostic]);
                
                // 高亮显示这条日志
                entry.highlighted = true;
            } catch (error) {
                console.error('Error linking error to config file:', error);
            }
        } catch (error) {
            console.error('Failed to create diagnostic for error:', error);
        }
    }

    /**
     * 更新状态栏项
     */
    private updateStatusBarItem(isStreaming: boolean): void {
        if (isStreaming) {
            this.statusBarItem.text = '$(terminal) Nginx Logs (streaming)';
            this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
        } else {
            this.statusBarItem.text = '$(terminal) Nginx Logs';
            this.statusBarItem.backgroundColor = undefined;
        }
    }

    /**
     * 清除所有诊断信息
     */
    clearDiagnostics(): void {
        this.errorDiagnosticCollection.clear();
    }

    /**
     * 释放资源
     */
    dispose(): void {
        this.stopLogStream();
        this.statusBarItem.dispose();
        this.outputChannel.dispose();
        this.errorDiagnosticCollection.dispose();
    }
} 